package org.familysearch.fsapi.gwt.server.dao.rest;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.log4j.Logger;
import org.familysearch.fsapi.gwt.common.client.entities.Temple;
import org.familysearch.fsapi.gwt.server.dao.DAOException;
import org.familysearch.fsapi.gwt.server.dao.IdentityDAO;
import org.familysearch.fsapi.gwt.server.dao.Session;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class IdentityDAOREST
		extends GenericRESTDAO<Temple, String>
		implements IdentityDAO
{

	private Logger log;
	
	private static String FS_API_HOST = "";
	private static String FS_IDENTITY_ENDPOINT = "";
	private static String USERNAME = "";
	private static String PASSWORD = "";
	private static String API_KEY = "";
	
	private Session session = null;
	private boolean authenticated = false;
	private Properties props = new Properties();
	
	public IdentityDAOREST()
	{
		log = Logger.getLogger(this.getClass().getName());

		try {
			loadFSAPIProperties();
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void loadFSAPIProperties() throws DAOException {

		log.debug("Loading fsapi.identity.properties");
		Properties masked = new Properties();
		try
		{
			String resourcePathRelativeToClasspath = "fsapi.identity.properties";
			ClassLoader cl = ClassLoader.getSystemClassLoader();
			URL url = cl.getResource(resourcePathRelativeToClasspath);
			if (url == null)
			{
					//		 Could not find resource on classpath
				throw new DAOException("DAO-0005", "Could not find the fsapi.properties file at " + resourcePathRelativeToClasspath);
			}
	
			InputStream rf = url.openStream();
			InputStream rfm = url.openStream();
			if (rf == null)
			{
					//		 Failed opening stream for this resource
			}
	
			props = new Properties();
			props.load(rf);
			masked.load(rfm);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
		// set props
		log.debug("Setting fsapi.identity.properties");
		masked.setProperty("PASSWORD", "******");
		masked.setProperty("API_KEY", "******");
		log.debug("fsapi.identity.properties=" + masked);
		FS_API_HOST = props.getProperty("FS_API_HOST");
		FS_IDENTITY_ENDPOINT = props.getProperty("FS_IDENTITY_ENDPOINT");
		API_KEY = props.getProperty("API_KEY");
		USERNAME = props.getProperty("USERNAME");
		PASSWORD = props.getProperty("PASSWORD");
		
		
	}

	public Session authenticate() throws DAOException {

		if( isAuthenticated() )
		{
			log.debug("Using current session id=" + session.getId());
			return session;
		}
		
		PostMethod method = new PostMethod(FS_API_HOST + FS_IDENTITY_ENDPOINT);
		method.addParameter("key", API_KEY);
		method.addParameter("username", USERNAME);
		method.addParameter("password", PASSWORD);
		
		try {
			client.executeMethod(method);
		} catch (HttpException e) {
			// TODO swallow HttpException and throw a DAOException
			e.printStackTrace();
		} catch (IOException e) {
			// TODO swallow IOException and throw a DAOException
			e.printStackTrace();
		}		
		
		InputStream responseBody = null;
		try {
			responseBody = method.getResponseBodyAsStream();
		} catch (IOException e) {
			// TODO swallow IOException and throw a DAOException
			e.printStackTrace();
		}
		
		log.debug("Login REST response status=" + method.getStatusLine());
		
		if( method.getStatusCode() == 200 )
		{
			// parse XML
			String xml = parseInputStream(responseBody);
			//System.out.println(xml);
			XPath xpath = XPathFactory.newInstance().newXPath();
			
			// obtain sessionID
			String sessionID = null; 
			try {
				InputSource source = new InputSource(new StringReader(xml));
				Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(source);
				sessionID = xpath.evaluate("//session/@id",document);
			} catch (XPathExpressionException e) {
				e.printStackTrace();
			} catch (SAXException e) {
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			log.debug("Obtained new valid session id=" + sessionID);
			session = new Session();
			session.setId(sessionID);
			setAuthenticated(true);
			
		}

		if( session == null )
		{
			throw new DAOException("DAO-0001", method.getStatusText() );
		}
		return session;
	}

	protected boolean isAuthenticated() {
		return authenticated;
	}

	protected void setAuthenticated(boolean authenticated) {
		this.authenticated = authenticated;
	}
}
